package com.jamal2362.apktool.fragment.files;

import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jamal2362.apktool.R;
import com.jamal2362.apktool.fragment.FilesFragment;
import com.jamal2362.apktool.util.FileUtils;
import com.jamal2362.apktool.util.MUtil;
import com.jamal2362.apktool.util.Settings;
import com.jamal2362.apktool.util.TextUtil;
import com.jamal2362.apktool.view.RefreshListView;

public class FilesAdapter extends BaseAdapter implements AdapterView.OnItemClickListener,AdapterView.OnItemLongClickListener,Refreshable {
	private final FilesFragment frag;
	private final List<Item> items;
	private final TextView path;
	public static final File rootDir = Environment.getExternalStorageDirectory();
	private BuildItem build;
	private File curDir;
	private String[] storages;
	private List<String> selectionList;
	private static RefreshListView mListView;
	private static Map<String, Integer> mScrollMap;
	private final FilenameFilter filter;
	private ImageView pasteView;
	private ImageView backView;
	private boolean selectMode;
	private int copyMode;
	private List<String> highlightFiles;

	private FilesAdapter(FilesFragment act, TextView path) {
		this.frag = act;
		this.path = path;
		this.filter = new FilenameFilter(){
			@Override
			public boolean accept(File p1, String p2) {
				return (isHiddenFiles() ? true : p2.charAt(0) != '.');
			}
		};
		this.pasteView = null;
		this.backView = null;
		this.storages = FileUtils.getStorages(act.getContext());
		this.mScrollMap = new HashMap<String, Integer>();
		build = null;
		curDir = null;
		items = new ArrayList<>(1024);
		selectionList = new ArrayList<String>();
		selectMode = false;
		copyMode = 0;
		highlightFiles = new ArrayList<String>();
	}

	@Override
	public void refresh() {
		refresh(curDir);
	}

	public FilesFragment getFrag() {
		return frag;
	}

	public boolean isHiddenFiles() {
		return Settings.getb(frag.getActivity(), "hide_files", false);
	}

	public void editPath() {
		final FragmentActivity act = frag.getActivity();
		final EditText newPath = new EditText(act);
		newPath.setSingleLine(true);
		newPath.setText(curDir.getAbsolutePath());
		final AlertDialog dialog = new AlertDialog.Builder(act).
			setView(newPath).
			setTitle(R.string.go_to).
			setPositiveButton(R.string.go_to, new DialogInterface.OnClickListener(){
				@Override
				public void onClick(DialogInterface p1, int p2) {
					File target = new File(newPath.getText().toString());
					refresh(target);
				}
			}).
			setNegativeButton(R.string.cancel, null).
			setNeutralButton(R.string.paste, null).
			create();
		dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
		dialog.setOnShowListener(new DialogInterface.OnShowListener() {
				@Override
				public void onShow(DialogInterface p1) {
					newPath.requestFocus();
					int dot = curDir.getAbsolutePath().lastIndexOf("/");
					if (dot <= 0) {
						newPath.selectAll();
					} else {
						newPath.setSelection(dot + 1, curDir.getAbsolutePath().length());
					}
				}
			});
		dialog.show();
		final String clip = TextUtil.readFromClipboard(act);
		final Button paste = dialog.getButton(DialogInterface.BUTTON_NEUTRAL);
		paste.setEnabled(clip != null);
		paste.setOnClickListener(new OnClickListener()
			{
				@Override
				public void onClick(View p1) {
					newPath.setText(clip);
				}
			});
		final Button ok = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
		newPath.addTextChangedListener(new TextWatcher(){
				@Override
				public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) {
					// TODO: Implement this method
				}
				@Override
				public void onTextChanged(CharSequence p1, int p2, int p3, int p4) {
					// TODO: Implement this method
				}
				@Override
				public void afterTextChanged(Editable p1) {
					if (p1.length() == 0) {
						ok.setEnabled(false);
						return;
					}
					File target = new File(p1.toString());
					if (!target.exists() || !target.isDirectory()) {
						ok.setEnabled(false);
						return;
					}
					ok.setEnabled(true);
				}
			});
	}

	public void createFileOrDir(final int mode) {
		FragmentActivity act = frag.getActivity();
		final EditText name = new EditText(act);
		name.setSingleLine(true);
		int title;
		if (mode == R.id.new_file)
			title = R.string.new_file;
		else
			title = R.string.new_dir;
		AlertDialog.Builder builder = new AlertDialog.Builder(act).
			setTitle(title).
			setView(name).
			setPositiveButton(R.string.ok, new DialogInterface.OnClickListener(){
				@Override
				public void onClick(DialogInterface p1, int p2) {
					File target = new File(curDir, name.getText().toString());
					if (mode == R.id.new_file) {
						try {
							target.createNewFile();
							frag.edit(target);
							refresh();
						} catch (IOException e) {}
					} else {
						if (target.mkdir())
							refresh(target);
					}
				}
			}).
			setNegativeButton(R.string.cancel, null);
		final AlertDialog dialog = builder.create();
		dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
		dialog.setOnShowListener(new DialogInterface.OnShowListener() {
				@Override
				public void onShow(DialogInterface p1) {
					name.requestFocus();
				}
			});
		dialog.show();
		final Button ok = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
		name.addTextChangedListener(new TextWatcher(){
				@Override
				public void beforeTextChanged(CharSequence p1, int p2, int p3, int p4) {
					// TODO: Implement this method
				}
				@Override
				public void onTextChanged(CharSequence p1, int p2, int p3, int p4) {
					// TODO: Implement this method
				}
				@Override
				public void afterTextChanged(Editable p1) {
					if (p1.length() == 0) {
						ok.setEnabled(false);
						return;
					}
					File target = new File(curDir, p1.toString());
					if (target.exists()) {
						ok.setEnabled(false);
						return;
					}
					ok.setEnabled(true);
				}
			});
		ok.setEnabled(false);
	}

	public void refresh(File dir) {
		try {
			if (!highlightFiles.isEmpty()) {
				highlightFiles.clear();
			}
			curDir = dir;
			BuildItem build = this.build;
			if (build != null && !build.isSubDir(dir))
				build = null;
			path.setText(dir.getAbsolutePath());
			items.clear();
			if (storages != null) {
				boolean badd = !dir.getAbsolutePath().equals("/");
				for (int i = 0; i < storages.length; i++) {
					if (curDir.getAbsolutePath().equals(storages[i]))
						badd = false;
				}
				if (badd)
					items.add(new BackItem(dir));
			}
			for (File f : dir.listFiles(filter)) {
				items.add(new FileItem(f, frag.getActivity()));
				if (f.isFile() && f.getName().equals("apktool.json") && dir.getAbsolutePath().startsWith(rootDir.getAbsolutePath()))
					build = new BuildItem(dir);
			}
			if (build != null)
				items.add(build);
			this.build = build;
			Collections.sort(items);
			updatePasteView();
			updateBackView();
			clearSelection();
			notifyDataSetChanged();

			if (mListView != null) {
				int scrollPosition = 0;
				if (!mScrollMap.isEmpty() && mScrollMap.containsKey(dir.getAbsolutePath())) {
					scrollPosition = mScrollMap.get(dir.getAbsolutePath());
				}
				mListView.setSelection(scrollPosition);
			}
		} catch (Exception e) {
			e.printStackTrace();
			TextUtil.st(frag.getActivity(), frag.getActivity().getString(R.string.failed_open, dir.getAbsolutePath()));
			refresh(rootDir);
		}
	}

	public void setHighlight(String file) {
		if (file != null)
			highlightFiles.add(file);
	}
	
	public boolean isHighlight(String file) {
		if (file != null)
			return highlightFiles.contains(file);
		else
			return false;
	}

	public void setPosition(final String path) {
		new Handler().postDelayed(new Runnable() {
				@Override
				public void run() {
					int p = 0;
					for (File f : curDir.listFiles(filter)) {
						if (f.getAbsolutePath().equals(path)) {
							mListView.setSelection(p);
							return;
						}
						p++;
					}
				}
			}, 100);
	}

	@Override
	public int getCount() {
		return items.size();
	}

	@Override
	public Object getItem(int p1) {
		return items.get(p1);
	}

	@Override
	public long getItemId(int p1) {
		return items.get(p1).hashCode();
	}

	public void setScrollPosition(String path) {
		if (mListView != null) {
			mScrollMap.put(path, mListView.getFirstVisiblePosition());
		}
	}

	public void setBackView(ImageView v) {
		this.backView = v;
	}

	public void setPasteView(ImageView v) {
		this.pasteView = v;
	}

	public void updateBackView() {
		if (backView == null)
			return;
		int draw;
		if (Settings.lightTheme) {
			draw = (isSelectionMode() ? R.drawable.ic_close : R.drawable.ic_undo);
			backView.setImageResource(draw);
		} else {
			draw = (isSelectionMode() ? R.drawable.ic_close_dark : R.drawable.ic_undo_dark);
			backView.setImageResource(draw);
		}
	}

	public void updatePasteView() {
		if (pasteView == null)
			return;
		String copy = Settings.gets(frag.getActivity(), "copy_file_path", null);
		if (copy == null) {
			pasteView.setVisibility(View.GONE);
		} else {
			pasteView.setVisibility(View.VISIBLE);
			if (curDir.canWrite()) {
				if (Settings.lightTheme)
					pasteView.setImageResource(R.drawable.ic_paste_light);
				else
					pasteView.setImageResource(R.drawable.ic_paste_dark);
			} else {
				pasteView.setImageResource(R.drawable.ic_paste_disable);
			}
		}
	}

	public boolean goBack() {
		if (selectMode) {
			clearSelection();
			return true;
		}
		if (curDir.getAbsolutePath().equals("/"))
			return false;
		if (storages != null) {
			for (int i = 0; i < storages.length; i++) {
				if (curDir.getAbsolutePath().equals(storages[i]))
					return false;
			}
		}
		if (curDir.equals(rootDir))
			return false;
		refresh(curDir.getParentFile());
		return true;
	}

	public void setSelection(String filepath) {
		selectMode = true;
		if (isSelected(filepath))
			selectionList.remove(filepath);
		else
			selectionList.add(filepath);
		if (selectionList.isEmpty()) {
			clearSelection();
		} else {
			updateBackView();
			notifyDataSetChanged();
		}
	}

	public List<String> getSelection() {
		return selectionList;
	}

	public File[] getSelectedFiles() {
		File[] res = new File[selectionList.size()];
		for (int i = 0; i < selectionList.size(); i++) {
			res[i] = new File(selectionList.get(i));
		}
		return res;
	}

	public boolean isApks() {
		for (int i = 0; i < selectionList.size(); i++) {
			if (!selectionList.get(i).endsWith(".apk"))
				return false;
		}
		return true;
	}

	public void selectAll(boolean inverse) {
		if (!inverse) {
			selectionList = null;
			selectionList = new ArrayList<String>();
		}
		selectMode = true;
		for (File f : curDir.listFiles(filter)) {
			setSelection(f.getAbsolutePath());
		}
		notifyDataSetChanged();
	}

	public void copyMode(int mode) {
		this.copyMode = mode;
	}

	public int getCopyMode() {
		return copyMode;
	}

	public void clearSelection() {
		selectMode = false;
		if (copyMode == 0) {
			selectionList = null;
			selectionList = new ArrayList<String>();
		}
		updateBackView();
		notifyDataSetChanged();
	}

	public boolean isSelected(String str) {
		if (str == null)
			return false;
		return selectionList.contains(str);
	}

	public void setSelectionMode(boolean on) {
		this.selectMode = on;
	}

	public boolean isSelectionMode() {
		return selectMode;
	}

	@Override
	public View getView(int p1, View p2, ViewGroup p3) {
		if (p2 == null) {
			p2 = frag.getLayoutInflater().inflate(R.layout.files_entry, p3, false);
		}
		int detailsFont = Settings.appFontSize - 4;
		int minHeight = MUtil.spAsPx(p2.getContext(), (Settings.appFontSize * 2 + detailsFont));
		p2.setMinimumHeight(minHeight);
		TextView name = p2.findViewById(R.id.name);
		name.setTextSize(TypedValue.COMPLEX_UNIT_SP, Settings.appFontSize);
		name.setTag("name-" + p1);
		TextView details = p2.findViewById(R.id.details);
		details.setTextSize(TypedValue.COMPLEX_UNIT_SP, detailsFont);
		details.setTag("details-" + p1);
		ImageView icon = p2.findViewById(R.id.icon);
		icon.setTag("icon-" + p1);
		items.get(p1).setup(p2, icon, name, details, this);
		return p2;
	}

	@Override
	public void onItemClick(AdapterView<?> p1, View p2, int p3, long p4) {
		Item item = items.get(p3);
		if (!isSelectionMode())
			if (item.edit(frag))
				return;
		if (item.click(p2, this))
			return;
		item.process(this);
	}

	@Override
	public boolean onItemLongClick(AdapterView<?> p1, View p2, int p3, long p4) {
		Item item = items.get(p3);
		return item.longClick(p2, this);
	}

	public void save(Bundle outState) {
		if (curDir == null || outState == null)
			return;
		outState.putString("CUR_DIR_PATH", curDir.getAbsolutePath());
	}

	public void setStorages(String[] stor) {
		this.storages = stor;
	}

	public void init(Bundle savedInstanceState) {
		// File rootDir = this.rootDir;
		File homeDir = new File(Settings.homeDir);
		if (!homeDir.exists() || !homeDir.isDirectory())
			homeDir = this.rootDir;
		if (savedInstanceState != null) {
			String cur_dir = savedInstanceState.getString("CUR_DIR_PATH", homeDir.getAbsolutePath());
			refresh(new File(cur_dir));
		} else {
			File f = new File(Settings.projectPath);
			if (f.exists() && f.isDirectory())
				refresh(f);
			else
				refresh(homeDir);
		}
	}

	public static FilesAdapter init(FilesFragment act, ListView files, TextView path) {
		mListView = (RefreshListView) files;
		FilesAdapter adapter = new FilesAdapter(act, path);
		files.setAdapter(adapter);
		files.setOnItemClickListener(adapter);
		files.setOnItemLongClickListener(adapter);
		return adapter;
	}
}
